package application;

import java.io.IOException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import external_sort_algorithms.ExternalMergeSort;
import file_utils.FileUtils;


public class LargeFileSorter {

	private static Options cmdOptions;
	
	//private static long BUFFER_SIZE_IN_BYTES = (long) (4 * FileUtils.GIGA * 0.75);
	
	private static long BUFFER_SIZE_IN_BYTES = 20;
		
	public static void main(String[] args) {
		cmdOptions = createOptions();
		
		if (args.length == 0)
			printUsageAndExit();
		
		CommandLine cmd = null;
		try {
			cmd = processCommandLineArgs(args);
		} catch (Exception e) {
			displayErrorAndExit(e.getMessage());
		}
		
		validateCmdOptions(cmd);
		
		String inputFilePath = cmd.getOptionValue("input");
		String outputFilePath = cmd.getOptionValue("output");
		
		try {
	        ExternalMergeSort.sort(inputFilePath, outputFilePath, BUFFER_SIZE_IN_BYTES);
        } catch (IOException e) {
	        displayErrorAndExit(e.getMessage());
        }
		
		System.out.println("Sorted file is written into " + outputFilePath);
	}
	
	@SuppressWarnings("static-access")
    public static Options createOptions() {
		Options options = new Options();
		
		Option input = OptionBuilder
				.withDescription("Input file name (to-be-sorted)")
				.hasArg(true)
				.withArgName("input")
				.withValueSeparator(' ')
				.create("input");
		
		Option output = OptionBuilder
				.withDescription("Output file name (sorted)")
				.hasArg(true)
				.withArgName("output")
				.withValueSeparator(' ')
				.create("output");
		
		Option help = OptionBuilder
				.withDescription("Help")
				.hasArg(false)
				.create("help");
		
		options.addOption(input);
		options.addOption(output);
		options.addOption(help);
		
		return options;
	}
	
	private static void validateCmdOptions(CommandLine cmd) {
		if (cmd.hasOption("help")) {
			printUsageAndExit();
		}
		
		if (!cmd.hasOption("input")) {
			System.err.println("An input file (--input) is required.");
			printUsageAndExit();
		}
		
		if (!cmd.hasOption("output")) {
			System.err.println("An output file (--output) is required.");
			printUsageAndExit();
		}
	}
	
	private static CommandLine processCommandLineArgs(String[] args) throws ParseException {
		CommandLineParser parser = new PosixParser();
		CommandLine cmd = parser.parse(cmdOptions, args);
		validateCmdOptions(cmd);
		return cmd;
	}
	
	private static void printUsageAndExit() {
		HelpFormatter fmt = new HelpFormatter();
		fmt.printHelp("LargeFileSorter", cmdOptions);
		System.exit(0);
	}
	
	private static void displayErrorAndExit(String msg) {
		System.err.println("ERROR: " + msg);
		printUsageAndExit();
	}
}
